﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.IO;

namespace Perceptron
{
    public class Perceptron
    {

        [STAThread]
        static void Main()
        {
            Console.WriteLine("Executando algoritmo Perceptron...");

            // Conjunto de treinamento - 14 exemplos com 6 parâmetros cada
            int[][] inputs = new int[14][];

            inputs[0] = new int[] { 0, 1, 1, 1, 0, 0 };
            inputs[1] = new int[] { 0, 1, 1, 0, 1, 1 };
            inputs[2] = new int[] { 0, 0, 0, 1, 0, 1 };
            inputs[3] = new int[] { 0, 1, 0, 1, 0, 1 };
            inputs[4] = new int[] { 0, 0, 0, 1, 1, 0 };
            inputs[5] = new int[] { 0, 1, 1, 0, 1, 1 };
            inputs[6] = new int[] { 0, 1, 1, 1, 0, 1 };
            inputs[7] = new int[] { 1, 0, 0, 0, 1, 0 };
            inputs[8] = new int[] { 1, 0, 0, 0, 1, 1 };
            inputs[9] = new int[] { 1, 1, 1, 1, 0, 0 };
            inputs[10] = new int[] { 1, 1, 0, 0, 1, 1 };
            inputs[11] = new int[] { 1, 0, 1, 0, 1, 0 };
            inputs[12] = new int[] { 1, 0, 1, 1, 0, 0 };
            inputs[13] = new int[] { 1, 0, 1, 0, 0, 0 };

            // Saídas dos treinamentos
            int[] outputs = new int[] { 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1 };

            int patternCount = 14;

            // Os erros iniciais são randômicos
            Random r = new Random();

            double[] weights = { r.NextDouble(), r.NextDouble(), r.NextDouble(), r.NextDouble(),
                                   r.NextDouble(), r.NextDouble() };

            // Taxa de Aprendizado
            double learningRate = 1;

            int iteration = 0;

            double globalError;

            int changedWeights = 0;

            do
            {
                globalError = 0;
                for (int p = 0; p < patternCount; p++)
                {
                    // Calcula output.
                    int output = Output(weights, inputs[p][0], inputs[p][1], inputs[p][2], inputs[p][3], inputs[p][4], inputs[p][5]);

                    // Calcula error.
                    double localError = (outputs[p] - output);

                    if (localError != 0)
                    {
                        // Atuzaliza pesos, já que o LocalError não é zero
                        for (int i = 0; i < 6; i++)
                        {
                            weights[i] += learningRate * localError * inputs[p][i];
                            changedWeights++;

                        }
                    }

                    // Converte erro para valor absoluto
                    globalError += Math.Abs(localError);
                }
                iteration++;
            } while (globalError != 0);


            for (int i = 0; i < 6; i++)
            {
                Console.WriteLine("Peso w" + (i+1) + ": " + weights[i]);

            }
            Console.ReadKey();
        }

        private static int Output(double[] weights, int x1, int x2, int x3, int x4, int x5, int x6)
        {
            double sum = x1 * weights[0] +
                            x2 * weights[1] +
                            x3 * weights[2] +
                            x4 * weights[3] +
                            x5 * weights[4] +
                            x6 * weights[5];

            return (sum >= 0) ? 1 : 0;
        }
    }
}
